package cn.edu.jxust.core.domain.repository.impl;

import cn.edu.jxust.common.domain.model.AuthorityBuild;
import cn.edu.jxust.common.domain.model.MenuBuild;
import cn.edu.jxust.common.domain.model.ResourceBuild;
import cn.edu.jxust.common.domain.entity.Account;
import cn.edu.jxust.common.domain.entity.RoleResource;
import cn.edu.jxust.common.domain.entity.SysResource;
import cn.edu.jxust.common.domain.dto.AuthorityVo;
import cn.edu.jxust.common.domain.dto.MenuVo;
import cn.edu.jxust.common.domain.dto.SysResourceVo;
import cn.edu.jxust.core.infrastructure.mapper.ResourceMapper;
import cn.edu.jxust.core.infrastructure.mapper.RoleResourceMapper;
import cn.edu.jxust.common.response.Result;
import cn.edu.jxust.common.response.ResultUtils;
import cn.edu.jxust.common.response.enums.ResultStatus;
import cn.edu.jxust.core.domain.repository.ResourceService;
import cn.edu.jxust.core.domain.repository.RoleService;
import cn.edu.jxust.core.infrastructure.util.BuildTreeUtils;
import cn.edu.jxust.core.infrastructure.util.Const;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;

/**
 * @author QiuKangming
 * @since 2020-06-29
 */
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, SysResource> implements ResourceService {

    @Resource
    private RoleResourceMapper roleResourceMapper;
    @Resource
    private ResourceMapper resourceMapper;
    @Resource
    private RoleService roleService;

    /**
     * 根据当前用户的角色类型, 查询出他可操作的角色类型, 如果可操作的角色类型中没有传过来的角色 id,
     * 则无相应的权限, 如果有, 再根据角色 id 获取相应的
     * 权限结果集合返回, 可操作的按钮, 增删改查
     * @param roleId 角色id
     * @return List<AuthorityVo>
     */
    @Override
    public Result getAuthorityTreeSetAuthced(Integer roleId) {

        try{
            //为角色分配权限
            //1. 传入的是需要分配权限的roleId
            //2. 首先判断当前角色是否越级
            //当前账户
            Account account = (Account) SecurityUtils.getSubject().getPrincipal();
            //获取可操作的角色id集合
            List<Integer> roleIds = roleService.getRoleIds(account.getRoleId());
            if(!roleIds.contains(roleId)){
                //越级操作
//                log.error("为角色分配权限越级操作: 当前角色id["+account.getRoleId()+"] 分配角色id["+roleId+"]");
                return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "权限不足, 为角色分配权限越级操作");
            }
            //3. 不是越级操作, 说明当前登录用户有该角色的操作权限, 可以对这个角色赋予权限, 返回当前角色拥有的权限
            //获取当前登录用户所拥有的权限集合
            List<SysResource> currResourceList;
            if(account.getRoleId().equals(Const.SUPER_ADMIN_ID)){
                currResourceList = resourceMapper.selectList(null);
            }else{
                //获取当前角色拥有的资源ids集合
                List<Integer> currAccountIds = roleResourceMapper.getResourceIdsByRoleId(account.getRoleId());
                if(currAccountIds.size() == 0){
                    //越级操作
//                    log.error("您的角色 ["+account.getRoleId()+"]"+"可以操作该角色, 但是您还未有任何权限, 所以不能分配");
                    return ResultUtils.resultWithoutData(ResultStatus.FAILED, "您可以操作该角色, 但是您还未有任何权限, 所以不能分配");
                }
                currResourceList = resourceMapper.selectBatchIds(currAccountIds);
            }
            //创建构建树形对象工具
            BuildTreeUtils<AuthorityBuild, AuthorityVo, SysResource> authcUtil =
                    new BuildTreeUtils<>(AuthorityBuild.class, AuthorityVo.class, SysResource.class);
            //将资源对象转换成 权限视图树形对象
            List<AuthorityVo> authorityVoList = authcUtil.buildVo(currResourceList);
            //4. 获取需要分配权限角色现有的权限id集合
            List<Integer> operaResourceIds = roleResourceMapper.getResourceIdsByRoleId(roleId);
            //5. 递归设置是否有权限标志字段
            this.setIsAuthc(true, authorityVoList, operaResourceIds);
            if(null != authorityVoList && !authorityVoList.isEmpty()){
                return ResultUtils.resultWithData(ResultStatus.SUCCESS, authorityVoList);
            }else{
                return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到任何权限信息");
            }

        } catch (Exception e){
//            log.error("ResourceServiceImpl --> getAuthorityTreeSetAuthced:" + e.getMessage());
            return ResultUtils.resultWithoutData(ResultStatus.FAILED);
        }

    }

    /**
     * 资源管理的时候获取的列表
     * 资源管理的话只有超级管理员可以对权限增删改查
     * @param roleId 角色id
     * @return List<SysResourceVo>
     */
    @Override
    public Result getAuthorityTreeByRoleId(Integer roleId) {

        //roleId是下拉框选择的角色id
        try{
            //获取 roleId 拥有的资源列表
            List<Integer> list = roleResourceMapper.getResourceIdsByRoleId(roleId);
            if(list.size() == 0){
//                log.warn("当前角色无任何可操作资源");
                return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "当前角色无任何可操作资源");
            }

            //获取权限集合
            //超级管理员获取全部权限, 因为有可能还有权限没分配的情况
            List<SysResource> authcList = resourceMapper.selectBatchIds(list);

            //封装 SysResourceVo 对象树
            BuildTreeUtils<ResourceBuild, SysResourceVo, SysResource> authcUtil =
                    new BuildTreeUtils<>(ResourceBuild.class, SysResourceVo.class, SysResource.class);
            List<SysResourceVo> voList = authcUtil.buildVo(authcList);
            if(voList != null && !voList.isEmpty()){
                return ResultUtils.resultWithData(ResultStatus.SUCCESS, voList);
            }else{
                return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到任何权限信息");
            }

        }catch (Exception e){
//            log.error("[ResourceServiceImpl --> getAuthorityTreeByRoleId] 发生异常: " + e.getMessage());
            return ResultUtils.resultWithoutData(ResultStatus.FAILED);
        }

    }


    /**
     * 删除资源
     * @param id 资源id
     * @return Result
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result delResource(Integer id) {

        try{
            //获取当前角色 id
            Integer currRoleId = ((Account) SecurityUtils.getSubject().getPrincipal()).getRoleId();
            if(!currRoleId.equals(Const.SUPER_ADMIN_ID)){
//                log.warn("非超级管理员删除资源信息");
                return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "您无权删除资源信息");
            }

            int i = resourceMapper.deleteById(id);
            //删除角色对应的该资源记录 也删除
            int j = roleResourceMapper.delete(new QueryWrapper<RoleResource>().eq("resource_id", id));
            return (i + j) >= 1
                    ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "删除该资源成功")
                    : ResultUtils.resultWithoutData(ResultStatus.FAILED, "删除该资源失败");
        }catch (Exception e){
            log.error("ResourceServiceImpl --> delResource:" + e.getMessage());
            return ResultUtils.resultWithoutData(ResultStatus.FAILED);
        }

    }

    /**
     * 增加资源
     * @param sysResourceVo 资源视图对象
     * @return Result
     */
    @Override
    public Result addResource(SysResourceVo sysResourceVo) {

        //获取当前角色 id
        Integer currRoleId = ((Account) SecurityUtils.getSubject().getPrincipal()).getRoleId();
        if(!currRoleId.equals(Const.SUPER_ADMIN_ID)){
//            log.warn("非超级管理员增加资源信息");
            return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "您没有权限增加资源信息");
        }
        return resourceMapper.insert(

                SysResource.builder()
                        .parentId(sysResourceVo.getParentId())
                        .resourceName(sysResourceVo.getResourceName())
                        .resourceCode(sysResourceVo.getResourceCode())
                        .resourceType(sysResourceVo.getResourceType())
                        .url(sysResourceVo.getUrl())
                        .icon(sysResourceVo.getIcon())
                        .orderNum(sysResourceVo.getOrderNum())
                        .createUsername(sysResourceVo.getCreateUsername())
                        .updateUsername(sysResourceVo.getUpdateUsername())
                        .build()

        ) == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "添加资源成功")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "添加资源失败");
    }

    /**
     * 修改资源信息
     * @param sysResourceVo 资源视图对象
     * @return Result
     */
    @Override
    public Result modifyResource(SysResourceVo sysResourceVo) {

        //获取当前角色 id
        Integer currRoleId = ((Account) SecurityUtils.getSubject().getPrincipal()).getRoleId();
        if(!currRoleId.equals(Const.SUPER_ADMIN_ID)){
//            log.warn("非超级管理员修改资源信息");
            return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "您无权修改资源信息");
        }

        if(null == sysResourceVo.getId()){
//            log.warn("修改资源信息时 id 为空");
            return ResultUtils.resultWithoutData(ResultStatus.PARAM_ERROR, "请提供正确的参数");
        }

        return resourceMapper.updateById(

                SysResource.builder()
                        .id(sysResourceVo.getId())
                        .parentId(sysResourceVo.getParentId())
                        .resourceName(sysResourceVo.getResourceName())
                        .resourceCode(sysResourceVo.getResourceCode())
                        .resourceType(sysResourceVo.getResourceType())
                        .url(sysResourceVo.getUrl())
                        .icon(sysResourceVo.getIcon())
                        .orderNum(sysResourceVo.getOrderNum())
                        .createUsername(sysResourceVo.getCreateUsername())
                        .updateUsername(sysResourceVo.getUpdateUsername())
                        .build()
        ) == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "修改资源信息成功")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "修改资源信息失败");
    }

    /**
     * 获取当前资源的子资源的个数
     * @param id 资源id
     * @return int
     */
    @Override
    public int selectSubPermsByPermissionId(Integer id) {

        return resourceMapper.selectSubPermsByPermissionId(id);

    }

    /**
     * 获取父权限集合
     * @return Result
     */
    @Override
    public Result getParentAuthcList() {

        //根据当前角色获取的父权限列表
        try{
            //获取当前角色 id
            Account account = (Account) SecurityUtils.getSubject().getPrincipal();
            Integer currRoleId = account.getRoleId();
            if(!currRoleId.equals(Const.SUPER_ADMIN_ID)){
//                log.warn("非超级管理员获取父权限信息");
                return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "您无权查看父权限信息");
            }

            //获取权限集合
            List<SysResource> sysResourceList = resourceMapper.selectList(new QueryWrapper<SysResource>()
                    .eq("resource_type", Const.RESOURCE)
                    .or()
                    .eq("resource_type", Const.SUB_RESOURCE));

            //封装 AuthorityVo 对象树工具
            BuildTreeUtils<AuthorityBuild, AuthorityVo, SysResource> authcUtil =
                    new BuildTreeUtils<>(AuthorityBuild.class, AuthorityVo.class, SysResource.class);
            //返回权限对象数
            List<AuthorityVo> voList = authcUtil.buildVo(sysResourceList);
            if(voList != null && !voList.isEmpty()){
                return ResultUtils.resultWithData(ResultStatus.SUCCESS, voList);
            }else{
                return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到任何父权限列表");
            }

        }catch (Exception e){
            log.error("[ResourceServiceImpl --> getAuthorityTreeByRoleId] 发生异常: " + e.getMessage());
            return ResultUtils.resultWithoutData(ResultStatus.FAILED);
        }

    }

    /**
     * 根据资源ids获取资源code列表
     * @param ids 资源ids
     * @return List<String>
     */
    @Override
    public List<String> getPermissionListByIds(List<Integer> ids) {

        return resourceMapper.getPermissionListByIds(ids);

    }

    /**
     * 根据角色 id 动态生成菜单列表
     * @param roleId 角色id
     * @return Result
     */
    @Override
    public Result getMenuTreeByRoleId(Integer roleId) {

        //根据角色获取树形菜单
        //2. 获取当前角色拥有的 资源 ids
        //3. 根据资源ids获取的资源进行资源对象树形化
        //4. 返回树形列表
        try{
            Account account = (Account) SecurityUtils.getSubject().getPrincipal();
            //获取资源 ids
            List<Integer> resourceIds = roleResourceMapper.getResourceIdsByRoleId(account.getRoleId());
            if(resourceIds.size() == 0){
//                log.warn("[ResourceServiceImpl]当前账户: " + account.getUsername() + " 没有任何权限, 获取不了菜单");
                return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "您没有任何权限, 无任何可操作菜单选项");
            }
            //根据 ids 获取资源对象集合
            List<SysResource> resources = resourceMapper.selectBatchIds(resourceIds);
            //创建构建树形对象工具
            BuildTreeUtils<MenuBuild, MenuVo, SysResource> authcUtil =
                    new BuildTreeUtils<>(MenuBuild.class, MenuVo.class, SysResource.class);
            //将资源对象转换成 权限视图树形对象
            List<MenuVo> voList = authcUtil.buildVo(resources);
            if(voList != null && !voList.isEmpty()){
                return ResultUtils.resultWithData(ResultStatus.SUCCESS, voList);
            }else{
                return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到任何菜单列表");
            }

        }catch (Exception e){
            log.error("ResourceServiceImpl --> getMenuTreeByRoleId:" + e.getMessage());
            return ResultUtils.resultWithoutData(ResultStatus.FAILED);
        }

    }

    /**
     * 递归设置某个字段
     * @param hasChildren 是否有子列表
     * @param authorityVoList 权限试图对象集合
     * @param operaResourceIds 操作资源的的ids集合
     */
    private void setIsAuthc(boolean hasChildren, List<AuthorityVo> authorityVoList, List<Integer> operaResourceIds){

        if(!hasChildren){
            return;
        }
        authorityVoList.forEach(vo -> {
            vo.setIsAuthced(operaResourceIds.contains(vo.getId()) ? 1 : 0);
            setIsAuthc(vo.getChildren() != null, vo.getChildren(), operaResourceIds);
        });

    }

}
